package com.mdn.steelcase.helper;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import com.mdn.steelcase.exception.ReflectionException;

public class ReflectionHelper {

	/**
	 * 
	 * @param className Nombre de la clase que contiene el m�todo a ejecutar
	 * @param methodName Nombre del m�todo a ejecutar
	 * @param params par�metros de entrada del m�todo
	 * @return
	 * @throws ReflectionException
	 */
	public static Object executeMethod(Class<?> className, String methodName, Object... params) throws ReflectionException{
		try {
		return executeMethod(((Class<?>) className).newInstance(), methodName, params);
		}catch(IllegalAccessException e){
			throw new ReflectionException(e.getMessage(), e);
		} catch (InstantiationException e) {
			throw new ReflectionException(e.getMessage(), e);
		}
	}

	/**
	 * 
	 * @param classInstance Instancia de la clase que contiene el m�todo a ejecutar
	 * @param methodName Nombre del m�todo a ejecutar
	 * @param params par�metros de entrada del m�todo
	 * @return
	 * @throws ReflectionException
	 */
	public static Object executeMethod(Object classInstance, String methodName, Object... params) throws ReflectionException{
		try{
			// Saca los tipos de los par�metros a partir de las clases de los elementos recibidos
			Class<?>[] types = new Class<?>[params.length]; 
			int i=0;
			for(Object o : params){
				types[i++] = o.getClass();
			}
			Method m = classInstance.getClass().getDeclaredMethod(methodName, types);
			// Forzamos a que el m�todo sea accesible aunque sea private o protected
			m.setAccessible(true);
			return (Modifier.isStatic(m.getModifiers()) ? m.invoke(null, params) : m.invoke(classInstance, params));		
		}catch(IllegalAccessException e){
			throw new ReflectionException(e.getMessage(), e);
		} catch (SecurityException e) {
			throw new ReflectionException(e.getMessage(), e);
		} catch (NoSuchMethodException e) {
			throw new ReflectionException(e.getMessage(), e);
		} catch (IllegalArgumentException e) {
			throw new ReflectionException(e.getMessage(), e);
		} catch (InvocationTargetException e) {
			throw new ReflectionException(e.getMessage(), e);
		}
	}

	/**
	 * 
	 * @param classInstance Instancia de la clase que contiene el m�todo a ejecutar
	 * @param fieldName Nombre del campo sobre el que se ejecuta el set
	 * @param param nuevo valor del campo
	 * @return
	 * @throws ReflectionException
	 */
	public static void executeSetMethod(Object classInstance, String fieldName, Object param) throws ReflectionException{
		try {
			Field field = classInstance.getClass().getDeclaredField(fieldName);
			field.setAccessible(true);
			field.set(classInstance, param);
		} catch (SecurityException e) {
			throw new ReflectionException(e.getMessage(), e);
		} catch (NoSuchFieldException e) {
			throw new ReflectionException(e.getMessage(), e);
		} catch (IllegalArgumentException e) {
			throw new ReflectionException(e.getMessage(), e);
		} catch (IllegalAccessException e) {
			throw new ReflectionException(e.getMessage(), e);
		}
	}

	/**
	 * 
	 * @param classInstance Instancia de la clase que contiene el m�todo a ejecutar
	 * @param fieldName Nombre del campo sobre el que se ejecuta el get
	 * @return
	 * @throws ReflectionException
	 */
	public static Object executeGetMethod(Object classInstance, String fieldName) throws ReflectionException{
		try {
			Field field = classInstance.getClass().getDeclaredField(fieldName);
			field.setAccessible(true);
			return field.get(classInstance);
		} catch (SecurityException e) {
			throw new ReflectionException(e.getMessage(), e);
		} catch (NoSuchFieldException e) {
			throw new ReflectionException(e.getMessage(), e);
		} catch (IllegalArgumentException e) {
			throw new ReflectionException(e.getMessage(), e);
		} catch (IllegalAccessException e) {
			throw new ReflectionException(e.getMessage(), e);
		}
	}

}
